using System;
using System.Collections.Generic;
using System.Linq;
using Gj;
using Gj.MapData;
using UnityEngine;

namespace Gj_sparrow.Framework.Services
{

    public interface AbilityEffect
    {
        int[] GetIds(string define);
        int[] GetSlice(string define);
        AbilityEffect MergeTo(AbilityEffect effect);
        void Fix();
    }

    public interface AbilityData
    {
        AbilityOwner GetAbilityInstance(DefineData data);
        Dictionary<int, Dictionary<string, AbilityEffect>> GetSourceEffect(int dataType, string key, int source, AbilityItem[] define);
        AbilityEffect BaseEffect();
        void FillOwner(PropDefineData instance, AbilityOwner owner);
        void ProcessEffect(PropDefineData instance, AbilityEffect effect);
    }

    public class AbilityItem
    {
        public int Key;
        public int Value;
    }

    public class AbilityKeyDefine
    {
        public int DataType;
        public string[] Keys;
        public AbilityEffect[] AbilityList;

        public AbilityEffect FromKey(string key)
        {
            var index = -1;
            for (var i = 0; i < Keys.Length; i++)
            {
                if (key == Keys[i])
                {
                    index = i;
                    break;
                }
            }
            if (index >= 0)
            {
                return AbilityList[index];
            }

            return null;
        }

    }

    public class AbilityOwner
    {
        public List<AbilityEffect> EffectSlice;

        public bool needChange;
        // 由source生成self和targetmap
        public List<int> SourceList;

        public List<AbilityItem[]> SourceAbility;
        //Source          map[AbilitySource]map[int]int
        public List<AbilityKeyDefine> SourceEffectAbility;

        public byte[] TargetType;
        public AbilityKeyDefine[] TargetList;
        public AbilityEffect SelfEffect;
        public AbilityEffect InheritEffect;

        public AbilityOwner()
        {
	        SourceList = new List<int>();
	        SourceAbility = new List<AbilityItem[]>();
	        SourceEffectAbility = new List<AbilityKeyDefine>();
        }
        public void Change()
        {
	        needChange = true;
        }

		public void ChangeSourceMap(int source, Dictionary<int, int> define)
		{
			var dd = new AbilityItem[define.Count];
			var i = 0;
			foreach (var keypair in define)
			{
				dd[i] = new AbilityItem(){Key = keypair.Key, Value = keypair.Value};
				i += 1;
			}

			this.ChangeSource(source, dd);
		}
		public void ChangeSource(int source, AbilityItem[] define) {
			SourceList.Add(source);
			SourceAbility.Add(define);
		}

		public void ChangeSourceEffect(int source, int dataType, Dictionary<string, AbilityEffect> group)
		{
			SourceEffectAbility.Add(AbilityService.GenerateDefine(dataType, group));
		}

		public void generateSelf(PropDefineData instance, AbilityData abilityData)
		{
			var targetMap = new Dictionary<int, Dictionary<string, AbilityEffect>>();
			var self = abilityData.BaseEffect();
			var DataType = instance.GetDataType().Value();
			var fd = instance.GetFieldDefine();
			var prop = instance.Receive(fd.Map["key"].PropType);
			var Key = Convert.ToString(prop.GetField("key"));
			for (var i = 0; i < SourceList.Count; i++)
			{
				var define = SourceAbility[i];
				var targetEffect = abilityData.GetSourceEffect(DataType, Key, SourceList[i], define);
				foreach (var keypair in targetEffect)
				{
					var targetDefine = AbilityService.GenerateDefine(keypair.Key, keypair.Value);

					// Debug.LogError("merge target start:"+keypair.Key);
					mergeTarget(DataType, Key, targetDefine, ref targetMap, self);
				}
			}

			for (var i = 0; i < SourceEffectAbility.Count; i++)
			{
				mergeTarget(DataType, Key, SourceEffectAbility[i], ref targetMap, self);
			}
			var targetType = new List<byte>();
			var targetList = new AbilityKeyDefine[targetMap.Count];
			// 从1开始，避免0判断有没有
			var ii = (byte)(1);
			foreach (var keypair in targetMap)
			{
				// Debug.LogError("merge ttarget:"+keypair.Key+"->"+targetType.Count);
				if (targetType.Count <= keypair.Key) {
					targetType.AddRange(new byte[keypair.Key-targetType.Count+1]);
				}
				targetType[keypair.Key] = ii;
				targetList[ii - 1] = AbilityService.GenerateDefine(keypair.Key, keypair.Value);
				ii += 1;
			}
			// Debug.LogError("merge ttarget end:"+DataType+"->"+targetType.Count);
			TargetType = targetType.ToArray();
			TargetList = targetList;
			SelfEffect = self;
		}

		public void generateInherit(PropDefineData instance , AbilityData abilityData)
		{
			// Debug.LogError("generateInherit");
			AbilityEffect effect = null;
			var DataType = instance.GetDataType().Value();
			var fd = instance.GetFieldDefine();
			var prop = instance.Receive(fd.Map["key"].PropType);
			var Key = Convert.ToString(prop.GetField("key"));

			foreach (var data in instance.Inherits())
			{
				// Debug.LogError(data);
				if (data == null) continue;
				var oo = abilityData.GetAbilityInstance(data);
				// Debug.LogError("ability effect inherits1:" + data.GetDataType() + "->" + Key);
				if (oo != null)
				{
					AbilityEffect targetEffect;
					// Debug.LogError("ability effect inherits1:" + data.GetDataType().Value() + "->" + Key+"  "+oo.TargetType.Length);
					if (oo.TargetType.Length > DataType)
					{
						var index = oo.TargetType[DataType];
						// Debug.LogError("ability effect inherits2:" + data.GetDataType().Value() + "->" + Key+"  "+index);
						if (index > 0) {
							var targetDefine = oo.TargetList[index - 1];
							targetEffect = targetDefine.FromKey(Key);
							if (targetEffect != null)
							{
								effect = targetEffect.MergeTo(effect);
								// fmt.Println("ability effect", DataType, data, oo.TargetType, Key, targetEffect.GetIds("direct"))
								// Debug.LogError("ability effect inherits3:" + data.GetDataType().Value() + "->" + Key);
							}

							targetEffect = targetDefine.FromKey(AbilityService.DefaultKey);
							if (targetEffect != null)
							{
								effect = targetEffect.MergeTo(effect);
								//fmt.Println("ability effect", DataType, data, oo.TargetType, "default", targetEffect.GetIds("direct"))
							}
						}
					}
				}
			}
			InheritEffect = effect;
		}

		public AbilityEffect Generate(PropDefineData instance , AbilityData abilityData)
		{
			// Debug.LogError("Generate");
			if (needChange) {
				needChange = false;
				abilityData.FillOwner(instance, this);
				generateSelf(instance, abilityData);
				generateInherit(instance, abilityData);
				if (InheritEffect != null) {
					InheritEffect.Fix();
					SelfEffect = InheritEffect.MergeTo(SelfEffect);
				}

				abilityData.ProcessEffect(instance, SelfEffect);
				SelfEffect.Fix();
				// 清理缓存
				SourceList.Clear();
				SourceAbility.Clear();
				SourceEffectAbility.Clear();
			}
			return SelfEffect;
		}

		public void mergeTarget(int DataType, string Key, AbilityKeyDefine source , ref Dictionary<int, Dictionary<string, AbilityEffect>> target, AbilityEffect self )
		{
			var dataType = source.DataType;
			var ok = target.TryGetValue(dataType, out var allGroup);
			if (!ok)
			{
				allGroup = new Dictionary<string, AbilityEffect>();
				target[dataType] = allGroup;
			}
			for(var index = 0; index< source.Keys.Length; index++)
			{
				var effect = source.AbilityList[index];
				var key = source.Keys[index];
				var ook = allGroup.TryGetValue(key, out var allEffect);
				if (!ook)
				{
					allEffect = null;
				}
				allGroup[key] = effect.MergeTo(allEffect);
				if (dataType == DataType && (key == Key || key == AbilityService.DefaultKey))
				{
					self = effect.MergeTo(self);
				}
			}
		}
    }

    public class AbilityService
    {
	    public const string DefaultKey = "";

	    public static AbilityOwner GenerateOwner()
	    {
		    var owner = new AbilityOwner();
		    return owner;
	    }
        public static AbilityKeyDefine GenerateDefine(int dataType , Dictionary<string, AbilityEffect> group)
        {
            var keys = new string[group.Count];
            var list = new AbilityEffect[group.Count];
            var i = 0;
            foreach (var keypair in group)
            {
                keys[i] = keypair.Key;
                list[i] = keypair.Value;
                i += 1;
                keypair.Value.Fix();
            }

            var define = new AbilityKeyDefine();
            define.DataType = dataType;
            define.Keys = keys;
            define.AbilityList = list;
            return define;
        }
    }

    public class StrategyCustom
    {
	    private Dictionary<int, int> Data;

	    public StrategyCustom()
	    {
		    Data = new Dictionary<int, int>();
	    }
	    public StrategyCustom(object obj)
	    {
		    Data = new Dictionary<int, int>();
		    foreach (object[] item in (object[])obj)
		    {
			    var key = Convert.ToInt32(item[1]);
			    var value = Convert.ToInt32(item[2]);
			    Data[key] = value;
		    }
	    }

	    public int Get(int id)
	    {
		    if (Data.ContainsKey(id)) return Data[id];
		    return 0;
	    }
    }

    public class StrategyEffect : AbilityEffect
    {
        // 获取指令
        public List<int> DirectIds;

        // 附加的持久buff
        public List<int> BuffIds;

        public ObjectAttr Attrs;
        private bool change;

        public StrategyEffect(AttrManager manager)
        {
            DirectIds = new List<int>();
            BuffIds = new List<int>();
            Attrs = new ObjectAttr(new int[0], manager);
        }
        public StrategyEffect(object obj, AttrManager manager)
        {
            DirectIds = new List<int>();
            BuffIds = new List<int>();
            Attrs = new ObjectAttr(new int[0], manager);
            if (obj == null) return;
            foreach (object[] item in (object[])obj)
            {
                var t = Convert.ToString(item[0]);
                var key = Convert.ToInt32(item[1]);
                var value = Convert.ToInt32(item[2]);
                switch (t)
                {
                    case "direct":
                        // Debug.LogError("direct:"+key);
                        DirectIds.Add(key);
                        break;
                    case "buff":
                        BuffIds.Add(key);
                        break;
                    case "attr":
                        // Debug.LogError("atttr:"+key+"->"+value);
                        Attrs.SetId(key, value);
                        break;
                }
            }
        }

        public static Dictionary<int, Dictionary<int, AbilityEffect>> TargetEffect(object obj, AttrManager manager)
        {
            var all = new Dictionary<int, Dictionary<int, AbilityEffect>>();
            if (obj == null) return all;
            var objs = (object[])obj;
            foreach (object[] item in objs)
            {
                var target = (object[])(item[0]);
                var effect = new StrategyEffect((object[])(item[1]), manager);
                var dataType = Convert.ToInt32(target[0]);
                var ok = all.TryGetValue(dataType, out var current);
                if (!ok)
                {
                    current = new Dictionary<int, AbilityEffect>();
                    all.Add(dataType, current);
                }
                // Debug.LogError("target effect:"+dataType);

                var ids = (object[])target[1];
                if (ids == null || ids.Length == 0)
                {
                    ids = new object[] { 0 };
                }
                foreach (var id in ids)
                {
                    current.Add(Convert.ToInt32(id), effect);
                }
            }

            return all;
        }

        public void Merge(StrategyEffect e)
        {
            DirectIds.AddRange(e.DirectIds);
            // Debug.LogErrorFormat("direct: {0}=>{1}", string.Join(",", e.DirectIds.Select(x => x.ToString()).ToArray()), string.Join(",", DirectIds.Select(x => x.ToString()).ToArray()));
            BuffIds.AddRange(e.BuffIds);
            Attrs.Merge(e.Attrs);
            change = true;
        }

        public void Compute()
        {
	        DirectIds = DirectIds.Distinct().ToList();
            BuffIds = BuffIds.Distinct().ToList();
        }

        public void Number(int number)
        {
            // Attrs.Number(number);
        }

        public StrategyEffect Copy()
        {
            var e = new StrategyEffect(Attrs._manager);
            e.DirectIds = DirectIds.ToList();
            e.BuffIds = BuffIds.ToList();
            e.Attrs = Attrs;
            return e;
        }

        // public void Process(buffMap map[int]*skill.Buff) {
        //  effect.DirectIds = DefaultModelData.DistinctDirect(effect.DirectIds)
        //  effect.BuffIds = DefaultSkillData.DistinctBuff(effect.BuffIds)
        //  for _, buffId := range effect.BuffIds {
        //   buff := buffMap[buffId]
        //   effect.InlineAttrs.MergeMap(buff.Attr)
        //  }
        //  effect.Attrs = effect.InlineAttrs.ToList()
        // }

        public int[] GetIds(string define)
        {
            switch (define)
            {
                case "direct":
                    return DirectIds.ToArray();
                case "buff":
                    return BuffIds.ToArray();
            }

            return null;
        }

        public int[] GetSlice(string define)
        {
            // Debug.LogError("define"+define);
            switch (define)
            {
                case "attr":
                    return Attrs.Data();
            }

            return null;
        }

        public AbilityEffect MergeTo(AbilityEffect e)
        {
            StrategyEffect ee;
            if (e == null)
            {
                ee = new StrategyEffect(Attrs._manager);
            }
            else
            {
                ee = (StrategyEffect)e;
            }

            ee.Merge(this);
            ee.Compute();
            return ee;
        }

        public void Fix()
        {
            if (!change)
            {
                return;
            }

            change = false;
        }

        public override string ToString()
        {
	        return Attrs.ToString();
        }
    }
}